package dic

/*
有道翻译API申请成功
API key：720242206
keyfrom：asd123b
创建时间：2014-05-09
网站名称：asd123b
网站地址：http://golangt.com
*/

import (
	"encoding/json"
	"fmt"
	//	"io"
	"os/exec"
	"regexp"
	"strconv"
	"strings"

	color "github.com/daviddengcn/go-colortext"
	"github.com/ggaaooppeenngg/util"
	"github.com/salviati/go-qt5/qt5"
)

const (
	APIKEY      = "720242206"
	URLTEMPLATE = "http://fanyi.youdao.com/openapi.do?keyfrom=asd123b&key=720242206&type=data&doctype=json&version=1.1&q="
)

var (
	regX *regexp.Regexp
	regY *regexp.Regexp
	exit chan bool
)

type basic struct {
	Phonetic    string   `json:"phonetic"`
	Uk_Phonetic string   `json:"uk-phonetic"`
	Us_Phonetic string   `json:"us-phonetic"`
	Explains    []string `json:"explains"`
}
type explainPair struct {
	Key   string   `json:"key"`
	Value []string `json:"value"`
}
type result struct {
	ErrorCode   int           `json:"errorCode"`
	Query       string        `json:"query"`
	Translation []string      `json:"translation"`
	Basic       basic         `json:"basic"`
	Web         []explainPair `json:"web"`
}

func init() {
	regX = regexp.MustCompile(`x:(\d+) `)
	regY = regexp.MustCompile(`y:(\d+) `)
	err := exec.Command("xclip", "-f", "/dev/null").Run()
	exit = make(chan bool)
	if err != nil {
		panic(err)
	}
}

func formatWebExplains(exs []explainPair) string {
	var explains []string
	for _, pair := range exs {
		explains = append(explains, fmt.Sprintf("%s->%s", pair.Key, strings.Join(pair.Value, " ")))
	}
	return strings.Join(explains, "\n")
}

func getMousePos() (int, int) {
	out, err := exec.Command("xdotool", "getmouselocation").Output()
	if err != nil {
		panic(err)
	}
	xy := fmt.Sprintf("%s", out)
	x := regX.FindStringSubmatch(xy)[1]
	y := regY.FindStringSubmatch(xy)[1]
	px, _ := strconv.Atoi(string(x))
	py, _ := strconv.Atoi(string(y))
	return px, py
}

func uiMain(ret result) {
	fmt.Println("begin ui")
	w := qt5.NewWidget()
	defer w.Close()
	w.SetSizev(300, 200)
	x, y := getMousePos()
	fmt.Println(x, y)
	w.SetPosv(x, y)
	w.SetWindowTitle("搜索结果")
	w.OnLeaveEvent(func(event *qt5.LeaveEvent) {
		fmt.Println("on event leave")
		w.Close()
		qt5.Exit(0)
	})
	lbox := qt5.NewVBoxLayout()
	defer lbox.Close()
	if ret.ErrorCode != 0 {
		lblErr := qt5.NewLabelWithText("查询失败")
		lbox.AddWidget(lblErr)

	} else {
		lblQuery := qt5.NewLabelWithText(fmt.Sprintf("单词:%s", ret.Query))
		lblTrans := qt5.NewLabelWithText(fmt.Sprintf("有道翻译:%s", strings.Join(ret.Translation, ",")))
		lblPhonetic := qt5.NewLabelWithText(fmt.Sprintf("音标:%s  ,美式:%s  ,英式:%s", ret.Basic.Phonetic, ret.Basic.Us_Phonetic, ret.Basic.Uk_Phonetic))
		lblExplains := qt5.NewLabelWithText(fmt.Sprintf("其他解释:%s", strings.Join(ret.Basic.Explains, "  |")))
		lblWebExplains := qt5.NewLabelWithText(fmt.Sprint("网络解释:\n", formatWebExplains(ret.Web)))
		lbox.AddWidget(lblQuery)
		lbox.AddWidget(lblTrans)
		lbox.AddWidget(lblPhonetic)
		lbox.AddWidget(lblExplains)
		lbox.AddWidget(lblWebExplains)
	}
	w.SetLayout(lbox)
	w.Show()
	fmt.Println("after show")
	<-exit
	fmt.Println("ui exit")
}

func GUITranslate(q string, done chan<- bool) {
	//wait会原子性地解锁Lock,并且挂起goroutine,等待下次的恢复执行，在Wait自身返回之前再锁上lock。不像其他系统Wait是不能返回的
	//除非被signal或者broadcast.因为当Wait第一次恢复的时候，lock是没有锁上的
	//调用者无法假设条件是满足的当Wait返回的时候，
	//在线程被唤醒到wait返回之间条件变量是随时都有可能被改变的，所以有必要在Wait返回后再
	//检查一次
	//写成 c.L.Lock() while(!conditon) c.Wait ; c.L.UnLock()

	//上面的注释与代码无关，是看条件变量的笔记，以为能在这个地方用。
	/*
		defer func() {
			fmt.Println("defer")
			//无视恐慌进行恢复
			if r := recover(); r != nil {
				fmt.Println("****************************")
				fmt.Println("*******panic***recover******")
				fmt.Println("****************************")
				fmt.Println(r)
				GUITranslate(q, done)
			}
		}()
	*/

	fmt.Println("before main")
	qt5.Main(func() {
		fmt.Println("after main")
		if q == "" || q == " " {
			return
		}
		fmt.Println("begin to get API")
		ret := apiGet(q)
		go uiMain(ret)
		//run is another thread
		fmt.Println("begin to run")
		qt5.Run()
		fmt.Println("after run")
		exit <- true
		fmt.Println("exit")
	})
	fmt.Println("main exit")
	done <- true
	fmt.Println("exit and done")
}

func apiGet(q string) result {
	if q == "" || q == " " {
		return result{
			ErrorCode: -1,
		}
	}
	fmt.Println("q is \n", q, "\n")
	var ret result
	fmt.Println("http " + URLTEMPLATE + q)
	res, err := util.Get(URLTEMPLATE + q)
	if err != nil {
		fmt.Println(err)
		ret.ErrorCode = -1
	} else {
		err = json.Unmarshal(res, &ret)
		if err != nil {
			panic(err)
		}
	}
	return ret
}

func Translate(q string) {
	var ret result
	res, err := util.Get(URLTEMPLATE + q)
	if err != nil {
		panic(err)
	}
	err = json.Unmarshal(res, &ret)
	if err != nil {
		panic(err)
	}
	if ret.ErrorCode != 0 {
		fmt.Println("获取解释失败,网络延迟")
	}
	color.ChangeColor(color.Green, true, color.Black, true)
	fmt.Printf("单词:%s\n", ret.Query)
	color.ResetColor()
	color.ChangeColor(color.Yellow, true, color.Black, true)
	fmt.Printf("有道翻译:%s\n", ret.Translation)
	color.ResetColor()
	color.ChangeColor(color.Red, true, color.Black, true)
	fmt.Printf("音标:%s,美式:%s,英式:%s\n", ret.Basic.Phonetic, ret.Basic.Us_Phonetic, ret.Basic.Uk_Phonetic)
	color.ResetColor()
	color.ChangeColor(color.Blue, true, color.Black, true)
	fmt.Printf("其他解释:\n")
	for _, explain := range ret.Basic.Explains {
		fmt.Printf("%s ", explain)
	}
	color.ResetColor()
	fmt.Printf("\n")
	color.ChangeColor(color.Magenta, true, color.Black, false)
	fmt.Printf("网络解释:\n")
	for _, pair := range ret.Web {
		fmt.Printf("%s -> %s\n", pair.Key, pair.Value)
	}
	color.ResetColor()
}
